#include <stdio.h>
#include <windows.h>
#include "include/pointers.h"

#define TELEPORT_PRIV	PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION

struct COORDS
{
	float	x;
	float	z;
	float	y;
}  __attribute__((packed));

void teleport_error(char *location)
{
	fprintf(stderr, 
		"Error %lu while %s.\n",
		GetLastError(),
		location);
	puts("==[  End Teleport  ]==\n");
}

void do_teleport(HANDLE rom_process, float distance)
{
	unsigned int	base;
	unsigned int	player;
	unsigned int	misc;
	unsigned int	teleport;
	
	struct COORDS	player_coords;
	struct COORDS	player_vectors;

	printf("==[ Begin Teleport ]==\n");

	/* Read base pointer, player pointer 'misc pointer' and 'teleport pointer' */
	if(ReadProcessMemory(rom_process, BASE_PTR, &base, 4, 0) == 0)
	{
		teleport_error("reading base pointer");
		return;
	}

	if(ReadProcessMemory(rom_process, (void *)(base + 0x598), &player, 4, 0) == 0)
	{
		teleport_error("reading player pointer");
		return;
	}
	
    if(ReadProcessMemory(rom_process, (void *)(player + 0xE8), &misc, 4, 0) == 0)
	{
		teleport_error("reading misc pointer");
		return;
	}
	
	if(ReadProcessMemory(rom_process, (void *)(misc + 0x80), &teleport, 4, 0) == 0)
	{
		teleport_error("reading teleport pointer");
		return;
	}

	/* Read X Y and Z coords */
	if(ReadProcessMemory(rom_process, (void *)(teleport + 0xB0), &player_coords, 12, 0) == 0)
	{
		teleport_error("reading player coordinates");
		return;
	}

	/* Read X Y and Z view direction vectors */
	if(ReadProcessMemory(rom_process, (void *)(player + 0x34), &player_vectors, 12, 0) == 0)
	{
		teleport_error("reading player vectors");
		return;
	}


	/* Calculate new locations and print some info */
	printf(	"Vectors:\n"
		"--------\n"
		"Xv: %.4f\n"
		"Yv: %.4f\n"
		"Zv: %.4f\n"
		"Before teleport:\n"
		"----------------\n"
		"X: %.3f\n"
		"Y: %.3f\n"
		"Z: %.3f\n",
		player_vectors.x,
		player_vectors.y,
		player_vectors.z,
		player_coords.x,
		player_coords.y,
		player_coords.z);
	
	player_coords.x += (player_vectors.x * distance);
	player_coords.z += (player_vectors.z * distance);
	player_coords.y += (player_vectors.y * distance);

	printf(	"After teleport:\n"
		"---------------\n"
		"X: %6.3f\n"
		"Y: %6.3f\n"
		"Z: %6.3f\n",
		player_coords.x,
		player_coords.y,
		player_coords.z);

	/* Write the new coordinates */
	if(WriteProcessMemory(rom_process, (void *)(teleport + 0xB0), &player_coords, 12, NULL) == 0)
	{
		teleport_error("writing player coordinates");
		return;
	}


	printf("==[  End Teleport  ]==\n\n");
}

int main(int argc, char **argv)
{
	HANDLE		rom_process;
	int		rom_pid;
	float		distance;
	
	/* get pid */
	if(argc < 2)
	{
		printf("If you don't know what this is or where to find it read the readme file.\nEnter the RoM process ID: ");
		scanf("%d", &rom_pid);
		puts("");
	}
	else
	{
		sscanf(argv[1], "%d", &rom_pid);
	}
	
	/* get distance */
	if(argc < 3)
	{
		printf("\nEnter the teleport distance (a good starting value is 50): ");
		scanf("%f", &distance);
	}
	else
	{
		sscanf(argv[2], "%f", &distance);
	}
	


	/* open process for reading */
	rom_process = OpenProcess(TELEPORT_PRIV, 0, rom_pid);
	if(rom_process == NULL)
	{
		puts("Failed to open process :(");
		return 1;
	}

	/* Loop for hotkeys*/
	while(1)
	{
		if(GetAsyncKeyState(VK_F8) & 0x00FF)
		{
			do_teleport(rom_process, distance);
		}
		Sleep(100);
	}

	return 0;
}
